1 Introduction

The goal of this document is to examine “escaped muons” that do not decay in the storage region and do not enter a calorimeter. Some of these muons may leave the storage ring altogether.

I generated art files of simulated events using mdc2 with different magnetic fields turned on or off (scenarios). We want to examine,

# Load necessary libraries
library(reticulate)  # Access to python
library(stringr)   # string functions
library(parallel)  # Parallel processing (built-in to R)
library(dplyr)     # data analysis
library(purrr)     # Functional programming
library(readr)     # Read formats
library(ggplot2)   # ploting
library(rgl)       # 3D plots
library(gridExtra) # Arranging plots
library(testthat)  # testing
#
library(readGallery) # Read art Gallery files
# Put all readGallery::useDataProduct calls here
useDataProduct('std::vector<gm2truth::TrackingActionArtRecord>')
useDataProduct('std::vector<gm2ringsim::GeantTrackRecord>')

2 Load the samples

Samples are located on the Fermilab dCache in the directory /pnfs/GM2/scratch/users/lyon/arr_20170321.

# Function to properly alter paths to accomodate XRootD
#    e.g. convert /pnfs/BLA --> root://fndca1.fnal.gov/pnfs/fnal.gov/usr/BLA
xrootd_ify <- function(aPath) paste0('root://fndca1.fnal.gov/pnfs/fnal.gov/usr', str_replace(aPath, '/pnfs', ''))

Determine the locations of the data files

# Determine locations of our files
system("ssh lyon@gm2gpvm04.fnal.gov 'ls /pnfs/GM2/scratch/users/lyon/arr_20170321/*/*.root'", intern=T) -> arrFiles
arrFiles %>% xrootd_ify() -> arrXrdFiles
arrXrdFiles
 [1] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243525_0/ARR_unified_everything_cyl.root"   
 [2] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243526_0/ARR_unified_noDipole_cyl.root"     
 [3] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243527_0/ARR_unified_noInflector_cyl.root"  
 [4] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243528_0/ARR_unified_noKickerQuads_cyl.root"
 [5] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243530_0/ARR_unified_noKicker_cyl.root"     
 [6] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243532_0/ARR_unified_noQuads_cyl.root"      
 [7] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243540_0/ARR_unified_everything_cyl.root"   
 [8] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243542_0/ARR_unified_noDipole_cyl.root"     
 [9] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243544_0/ARR_unified_noInflector_cyl.root"  
[10] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243547_0/ARR_unified_noKickerQuads_cyl.root"
[11] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243548_0/ARR_unified_noKicker_cyl.root"     
[12] "root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243552_0/ARR_unified_noQuads_cyl.root"      

Pull out the scenaios (these will be in the same order as the file names)

scenarios <- str_match(arrFiles, 'arr_20170321/.+unified_(.+)_cyl')[,2]
scenarios %>% unique()
[1] "everything"    "noDipole"      "noInflector"   "noKickerQuads" "noKicker"      "noQuads"      

Let’s look at the contents of these files (they’re all the same, so we’ll just do one) gm2 v7_04_00 will have product_sizes_dumper.

stringToRun <- str_interp(
  "ssh lyon@gm2gpvm04.fnal.gov 'source /cvmfs/gm2.opensciencegrid.org/prod7/g-2/setup
  setup gm2 v7_04_00 -q prof ; 
  product_sizes_dumper ${aFile} | grep ::'", 
  list(aFile = arrFiles[1])
)
#
system(stringToRun)
        1410762186      0.456 gm2truth::MagnetIronAndCryoArtRecords_artg4_magnetIronAndCryostat_mdc2arr.
         660570363      0.214 gm2truth::TrackingActionArtRecords_artg4__mdc2arr.
         637307490      0.206 gm2truth::TrajectoryArtRecords_artg4__mdc2arr.
         240738334      0.078 gm2ringsim::GeantTrackRecords_artg4_KeepStepsAction_mdc2arr.
         118035827      0.038 gm2truth::RingArtRecords_artg4_Ring_mdc2arr.
          12078805      0.004 gm2truth::GhostDetectorArtRecords_artg4_GhostCylinderDetector_mdc2arr.
           4482185      0.001 art::RNGsnapshots_randomsaver__mdc2arr.
           4086898      0.001 gm2truth::RingTrackingPlaneArtRecords_artg4_RingTrackingPlanes_mdc2arr.
           1373178      0.000 gm2truth::GhostDetectorArtRecords_artg4_GhostNearWorldDetector_mdc2arr.
           1185772      0.000 gm2truth::PhaseSpaceArtRecord_artg4__mdc2arr.
             36971      0.000 art::TriggerResults_TriggerResults__mdc2arr.

3 Escaping muons from the Tracking Action data

The tracking action data has birth and death data for every Geant track.

3.1 Load Tracking Action data

We’ll capture this information for the primary muon and its first generation daughters. See gm2dataproducts/mc/actions/track/TrackingActionArtRecord.hh.

We need a readGallery reader python class. Generate with,

readerClassSkel('gm2truth::TrackingActionArtRecord', writeFile = 'trackingActionReader.py')

Here is the reader,

read_file('trackingActionReader.py') %>% cat
from readGallery import GalleryReaderBase  # Necessary for the base class

class TrackingActionArtRecordReader(GalleryReaderBase):
  def __init__(self, inputTag):
    GalleryReaderBase.__init__(self, inputTag)
    self.names = ['fileEntry', 'eventEntry', 'trackType', 'trackID', 
                  'parentTrackID', 'turn', 'volumeUID', 'status',  'p', 'e', 'x', 'y', 'z', 'px', 'py', 'pz']

  def prepare(self, ROOT, ev):
    GalleryReaderBase.prepare(self, ROOT, ev)
    self.getValidHandle = ev.getValidHandle(ROOT.vector(ROOT.gm2truth.TrackingActionArtRecord))

  def fill(self, ROOT, ev):

    validHandle = self.getValidHandle(self.inputTag)  # Get the valid handle for 
                                                      # gm2truth::TrackingActionArtRecord

    if not validHandle.empty():                       # Does it have data?

      p = validHandle.product()                       # Get the corresponding data product (maybe a vector)

      # Fill from gm2truth::TrackingActionArtRecord
      for e in p:                             # Loop over elements and fill
        
        # Only accept the primary muon death and its first generation daughters birth
        if (e.trackID == 1 and e.status == 1) or (e.parentTrackID == 1 and e.status == 0):
        
          self.vals.append(
            [ ev.fileEntry(), ev.eventEntry(), e.trackType, e.trackID, 
              e.parentTrackID, e.turn, e.volumeUID, e.status, e.p, e.e, 
              e.x, e.y, e.z, e.px, e.py, e.pz ])

    return True

Make the reader class and object

trackingActionReaderC <- createReaderClass_from_file('trackingActionReader.py')$TrackingActionArtRecordReader

We have many files to process. Let’s do this reading in parallel.

We need to create a reader object per parallel job

trackingActionReaders <- map(1:length(arrXrdFiles), function(i) trackingActionReaderC(artInputTag("artg4")))

Load the data

jobs <- lapply(1:length(arrXrdFiles), function(i) getGalleryData(arrXrdFiles[i], trackingActionReaders[[i]]) %>%
                                                    mcparallel(name=i))
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243525_0/ARR_unified_everything_cyl.root
Closing file, read 663158402 bytes in 161 transactions
Timings: Overall time = 200.338 s
Time per event: min=0.000   mean=0.019   max=7.364
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243526_0/ARR_unified_noDipole_cyl.root
Closing file, read 657073380 bytes in 158 transactions
Timings: Overall time = 228.757 s
Time per event: min=0.000   mean=0.022   max=27.028
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243527_0/ARR_unified_noInflector_cyl.root
Closing file, read 668231087 bytes in 160 transactions
Timings: Overall time = 208.320 s
Time per event: min=0.000   mean=0.020   max=16.990
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243528_0/ARR_unified_noKickerQuads_cyl.root
Closing file, read 664723747 bytes in 161 transactions
Timings: Overall time = 200.955 s
Time per event: min=0.000   mean=0.019   max=8.426
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243530_0/ARR_unified_noKicker_cyl.root
Closing file, read 666316280 bytes in 160 transactions
Timings: Overall time = 234.668 s
Time per event: min=0.000   mean=0.022   max=17.103
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243532_0/ARR_unified_noQuads_cyl.root
Closing file, read 664218464 bytes in 136 transactions
Timings: Overall time = 535.363 s
Time per event: min=0.000   mean=0.053   max=334.559
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243540_0/ARR_unified_everything_cyl.root
Closing file, read 660527554 bytes in 161 transactions
Timings: Overall time = 266.787 s
Time per event: min=0.000   mean=0.026   max=21.746
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243542_0/ARR_unified_noDipole_cyl.root
Closing file, read 656304716 bytes in 158 transactions
Timings: Overall time = 209.096 s
Time per event: min=0.000   mean=0.021   max=17.045
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243544_0/ARR_unified_noInflector_cyl.root
Closing file, read 668176375 bytes in 160 transactions
Timings: Overall time = 209.131 s
Time per event: min=0.000   mean=0.020   max=11.414
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243547_0/ARR_unified_noKickerQuads_cyl.root
Closing file, read 664807569 bytes in 161 transactions
Timings: Overall time = 216.531 s
Time per event: min=0.000   mean=0.021   max=17.764
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243548_0/ARR_unified_noKicker_cyl.root
Closing file, read 666316217 bytes in 160 transactions
Timings: Overall time = 227.132 s
Time per event: min=0.000   mean=0.022   max=13.152
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243552_0/ARR_unified_noQuads_cyl.root
Closing file, read 665617262 bytes in 161 transactions
Timings: Overall time = 221.986 s
Time per event: min=0.000   mean=0.021   max=9.361
trackingActionReturns <- mccollect(jobs)

Let’s merge all of the output.

trackingActionDF <- map_df(1:length(trackingActionReaders), 
                           function(i) galleryReader_df(trackingActionReaders[[i]]) %>% mutate(scenario=scenarios[i], 
                                                                                               fileEntry=i))
trackingActionDF
write_rds(trackingActionDF, 'trackingActionDF.rds')

How many muons per file?

trackingActionDF %>% filter(trackID==1) %>% group_by(scenario, fileEntry) %>% tally()

3.1.1 Add Volume Names

We need to turn the volume IDs into volume names. The volume IDs change for each file. We can run a small art job to determine the volume ID to name tables.

runForVolIDString <- function(i) {
  str_interp(
    "PVS_CSVOUT=${csvout}_${i}_volNames.csv gm2 -c ${fclPath}/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 ${aFile}",
    list( csvout=scenarios[i], i=i, fclPath=Sys.getenv("MRB_BUILDDIR"), aFile=arrXrdFiles[i]) 
  )
}
runForVolIDStrings <- sapply(1:length(arrXrdFiles), runForVolIDString)
runForVolIDStrings
 [1] "PVS_CSVOUT=everything_1_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243525_0/ARR_unified_everything_cyl.root"       
 [2] "PVS_CSVOUT=noDipole_2_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243526_0/ARR_unified_noDipole_cyl.root"           
 [3] "PVS_CSVOUT=noInflector_3_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243527_0/ARR_unified_noInflector_cyl.root"     
 [4] "PVS_CSVOUT=noKickerQuads_4_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243528_0/ARR_unified_noKickerQuads_cyl.root" 
 [5] "PVS_CSVOUT=noKicker_5_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243530_0/ARR_unified_noKicker_cyl.root"           
 [6] "PVS_CSVOUT=noQuads_6_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243532_0/ARR_unified_noQuads_cyl.root"             
 [7] "PVS_CSVOUT=everything_7_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243540_0/ARR_unified_everything_cyl.root"       
 [8] "PVS_CSVOUT=noDipole_8_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243542_0/ARR_unified_noDipole_cyl.root"           
 [9] "PVS_CSVOUT=noInflector_9_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243544_0/ARR_unified_noInflector_cyl.root"     
[10] "PVS_CSVOUT=noKickerQuads_10_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243547_0/ARR_unified_noKickerQuads_cyl.root"
[11] "PVS_CSVOUT=noKicker_11_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243548_0/ARR_unified_noKicker_cyl.root"          
[12] "PVS_CSVOUT=noQuads_12_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243552_0/ARR_unified_noQuads_cyl.root"            

Let’s run the art jobs in parallel

jobs <- lapply(1:length(arrXrdFiles), function(i) mcparallel(system( runForVolIDStrings[i], intern=T ), name=i))
res <- mccollect(jobs)
running command 'PVS_CSVOUT=noKickerQuads_10_volNames.csv gm2 -c /home/me/gm2/renee_arr/build_slf7.x86_64/gm2analyses/fcl/physicalVolumeStoreToFile.fcl -n 1 root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243547_0/ARR_unified_noKickerQuads_cyl.root' had status 20

and load the CSV files.

jobs <- lapply(1:length(arrFiles), function(i) 
  str_interp("${scn}_${i}_volNames.csv", list(scn=scenarios[i], i=i)) %>%
    read_csv(col_names=c("volumeUID", "volName")) %>% mcparallel(name=i) )
#
volNameTables <- mccollect(jobs)
volNameDF <- map_df(1:length(volNameTables), function(i) 
                      volNameTables[[i]] %>% mutate(scenario=scenarios[i],
                                                    fileEntry=i))
volNameDF
write_rds(volNameDF, 'volNameDF.rds')

Now we merge with the tracking action data frame

trackingActionDF %>% inner_join(volNameDF) %>% 
  select(scenario, fileEntry, eventEntry, volName, everything()) -> trackingActionNDF
Joining, by = c("fileEntry", "volumeUID", "scenario")
trackingActionNDF

3.2 How many muons decay in the storage region?

These muons decay in the storage region (not quite the same as “stored”),

trackingActionNDF %>% filter(trackID==1, volName=='ArcSection[00]') %>% 
  group_by(scenario, fileEntry) %>% tally()

Interesting! So, from this, only 0.575% decay in the storage region for the “all on” (or everything) sample. That seems rather low. But continuing.

write_rds(trackingActionNDF, 'trackingActionNDF.rds')

3.3 Where do muons go to die?

trackingActionNDF %>% filter(trackID == 1) %>% group_by(scenario, volName) %>% tally()

It may be nice to categorize the volume names by area (e.g. “Arc”, “bellows”, “Ring”, “Inflector”).

# Pull out the first word in camel case (see http://stackoverflow.com/questions/29916065/how-to-do-camelcase-split-in-python)
camelCaseSplit <- function(s) str_split(s, '(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])')
# Test the above
expect_equal(camelCaseSplit("RingPoleTipUpper")[[1]], c("Ring", "Pole", "Tip", "Upper"))
expect_equal(camelCaseSplit("ringPoleTipUpper")[[1]], c("ring", "Pole", "Tip", "Upper"))
expect_equal(camelCaseSplit("world")[[1]], c("world"))
expect_equal(camelCaseSplit("ringPole")[[1]], c("ring", "Pole"))
# We really just want the first word
takeFirstCamel <- function(s) camelCaseSplit(s) %>% map_chr(function(s) s[1])
takeFirstCamel("RingPoleTipUpper") %>% expect_equal("Ring")
takeFirstCamel("ringPoleTipUpper") %>% expect_equal("ring")
takeFirstCamel("world") %>% expect_equal("world")
takeFirstCamel("ringPole") %>% expect_equal("ring")
takeFirstCamel(c("ringPoleTipUpper", "world")) %>% expect_equal(c("ring", "world"))

Don’t confuse RingTrackingPlane with the iron

makeVolCategory <- function(s) ifelse( str_detect(s, 'RingTracking'),
                                       "RngTrkPlane",
                                       takeFirstCamel(s))
makeVolCategory(c("RingBottom", "RingTrackingPlane[8]", "world")) %>% expect_equal(c("Ring", "RngTrkPlane", "world"))
trackingActionNDF %>% mutate(volCategory = volName %>% makeVolCategory()) -> trackingActionNVDF
trackingActionNVDF

Show count by category

trackingActionNVDF %>% filter(trackID == 1) %>% group_by(scenario, volCategory) %>% tally() -> volCatTally
volCatTally %>% mutate(perc = n/20000 * 100) -> volCatTally
volCatTally

Let’s plot!

trackingActionNVDF %>% filter(trackID ==1) %>% ggplot(aes(x=volCategory, group=scenario)) + 
  geom_bar()

ggplot(volCatTally, aes(x = volCategory, y=perc, fill=scenario)) + 
  geom_bar(stat="Identity", width=0.5, position="dodge")

Can’t really see non-Ring/world ones. Let’s split them out.

# Function to make this easy
plotit <- function(d) ggplot(d, aes(x = volCategory, y=perc, fill=scenario) ) + 
  geom_bar(stat="Identity", width=0.5, position="dodge") + 
  xlab("Volume category") + ylab("Percent")
volCatTally %>% filter(volCategory %in% c("Ring", "world")) %>% plotit -> p1
volCatTally %>% filter(! volCategory %in% c("Ring", "world")) %>% plotit -> p2
grid.arrange(p1, p2)

Let’s see where they die

# See https://rpubs.com/hadley/97970 for how to wrap a multipart ggplot2 component
plotCommon <- function () {
  list(
    facet_wrap(~scenario),
    guides(col = guide_legend(override.aes = list(size=5, alpha=1))),
    scale_color_discrete(name="Volume\nCategory"),
    labs(x="z (mm)", y="x (mm)"),
    theme_minimal()
  )
}
trackingActionNVDF %>% filter(trackID == 1) %>% 
  ggplot( aes(x=z, y=x, color=volCategory)) + 
    geom_point(alpha=0.1) + 
    ggtitle('Where Muons Die') +
    plotCommon()

Here it is without the ring losses, which dominate

trackingActionNVDF %>% filter(trackID == 1, volCategory != 'Ring') %>% 
  ggplot( aes(x=z, y=x, color=volCategory)) + 
    geom_point(alpha=0.5) + 
    ggtitle("Where Muons Die", subtitle = "Ring escapees excluded for clarity") +
    plotCommon()

3.4 Does it make sense for so many muons to stop in the iron?

We have 3 GeV muons. Does it make sense that the vast majority of them stop in the iron? A table shows the Continuous Slow Down Approximation range of muons (CSDA). For a 3 GeV muon in iron, the CSDA is \(1.825 \times 10^{3}\) g/cm\(^2\). The density \(\rho\) is 7.874 g/cm\(^3\). So, where \(R\) is range,

\[R = \text{CSDA}/\rho\] Range is thus 2.32 m. This is begger than the width of the iron, but remember that the muons come in at an oblique angle. We’ll have to prove this.

4 How far do muons go in the iron?

We have the Geant stepping information, so we should be able to figure out how far the muons go in the iron.

Here is the Gallery reader,

read_file('GeantTrackReader.py') %>% cat
from readGallery import GalleryReaderBase  # Necessary for the base class

class GeantStepReader(GalleryReaderBase):
  def __init__(self, inputTag, eventsToFill = []):
    GalleryReaderBase.__init__(self, inputTag)
    self.names = ['fileEntry', 'eventEntry', 'trackID', 'globalStepNum', 'totalEnergyDeposit', 
                  'stepLength', 'volumeUID', 
                  'x', 'y', 'z', 'px', 'py', 'pz']
    self.eventsToFill = eventsToFill
    print self.eventsToFill

  def prepare(self, ROOT, ev):
    GalleryReaderBase.prepare(self, ROOT, ev)
    self.getValidHandle = ev.getValidHandle(ROOT.vector(ROOT.gm2ringsim.GeantTrackRecord))

  def fill(self, ROOT, ev):

    # Do we care about this event - if not then don't bother looking?
    if self.eventsToFill and not ev.eventEntry() in self.eventsToFill:
      return True
      
    print 'Reading entry %s' % ev.eventEntry()

    validHandle = self.getValidHandle(self.inputTag)  # Get the valid handle for gm2ringsim::GeantTrackRecord

    if not validHandle.empty():                       # Does it have data?

      p = validHandle.product()                       # Get the corresponding data product (maybe a vector)

      # Fill from gm2ringsim::GeantStep
      for e in p:                             # Loop over elements and fill
      
        # Get the steps
        for f in e.steps():

          self.vals.append(
            [ ev.fileEntry(), ev.eventEntry(), e.trackID(), f.globalStepNum(), 
            f.totalEnergyDeposit(), f.stepLength(), f.volumeUID(), 
            f.pos()[0], f.pos()[1], f.pos()[2], 
            f.p()[0], f.p()[1], f.p()[2] ])
            
        # If we're on the last event, don't bother reading any more
        if self.eventsToFill and ev.eventEntry() == self.eventsToFill[-1]:
          return False

    return True
geantStepReaderC <- createReaderClass_from_file('GeantTrackReader.py')$GeantStepReader

4.1 Muon distance in iron for one event

Let’s find an event where the muon did in the iron.

trackingActionNVDF %>% filter(trackID == 1, volName == 'RingYokeBottom')

Event 4 looks good.

geantStepOne <- geantStepReaderC(artInputTag('artg4:KeepStepsAction'), tuple(as.integer(4)))
(4,)
getGalleryData(arrXrdFiles[1], geantStepOne)
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243525_0/ARR_unified_everything_cyl.root
Reading entry 4
gsOneDF <- galleryReader_df(geantStepOne)

Merge in volume names

gsOneDF %>% mutate(fileEntry = 1) %>%
  inner_join(volNameDF) %>% 
  select(volName, everything()) -> gsOneDF
Joining, by = c("fileEntry", "volumeUID")
gsOneDF

Let’s make a 3D plot of this path

ring <- cylinder3d( center=rbind(c(0,-90, 0), c(0,90,0)),
                    radius=7112,
                    sides=20, closed = F)

Let’s do volume categories again.

gsOneDF %>% mutate(volCategory = volName %>% makeVolCategory %>% as.factor) -> gsOneDF

Let’s plot the path. Note that I have to make the legend separately since legend3d looks awful.

# lengend3d looks terrible - so do a regular legend
plot(1, type='n', axes=FALSE, ann=FALSE)
with(gsOneDF,
  legend("top", legend=unique(volCategory), col=as.integer(unique(volCategory)), pch=19)
)

clear3d()
with(gsOneDF,{
     plot3d(x=x, y=y, z=z, type='p', col = as.integer(volCategory), ylim=c(-400, 400))
})
plot3d(ring, add=T, alpha=0.2)
view3d(phi=90, theta=-90)
rglwidget()

How much energy loss and distance traveled in each volume category

gsOneDF %>% group_by(volCategory) %>% summarize(totalDist_meters=round(sum(stepLength)/1000, 2), 
                                                totalELoss_MeV=round(sum(totalEnergyDeposit), 1),
                                                nSteps = n())

Ok - I believe this (note that the y scale is very small compared to the x,z scales - so the muon acutally travels quite far in x & z). The muon travels about 2.4m in the iron and ranges out. Physics (and Geant) work!

Let’s try another one

geantStepOneA <- geantStepReaderC(artInputTag('artg4:KeepStepsAction'), tuple(as.integer(10)))
(10,)
getGalleryData(arrXrdFiles[1], geantStepOneA)
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243525_0/ARR_unified_everything_cyl.root
Reading entry 10
Timings: Overall time = 178.569 s
Time per event: min=0.000   mean=0.100   max=1.101
gsOneADF <- galleryReader_df(geantStepOneA)
gsOneADF %>% mutate(fileEntry = 1) %>%
  inner_join(volNameDF) %>% 
  mutate(volCategory = volName %>% makeVolCategory %>% as.factor)%>% 
  select(volName, volCategory, everything()) -> gsOneADF
Joining, by = c("fileEntry", "volumeUID")
gsOneADF
gsOneADF %>% group_by(volCategory) %>% summarize(totalDist_meters=round(sum(stepLength)/1000, 2), 
                                                totalELoss_MeV=round(sum(totalEnergyDeposit), 1),
                                                nSteps = n()) -> gsOneADFSum
gsOneADFSum

Check sums

gsOneADFSum %>% summarize(sum(totalELoss_MeV))
gsOneADF %>% summarize(sum(totalEnergyDeposit))
# lengend3d looks terrible - so do a regular legend
plot(1, type='n', axes=FALSE, ann=FALSE)
with(gsOneADF,
  legend("top", legend=unique(volCategory), col=as.integer(unique(volCategory)), pch=19)
)

clear3d()
with(gsOneADF,{
     plot3d(x=x, y=y, z=z, type='p', col = as.integer(volCategory), ylim=c(-400, 400), xlim=c(-10000, 10000),
            zlim=c(-10000, 10000))
})
plot3d(ring, add=T, alpha=0.2)
view3d(phi=90, theta=-90)
rglwidget()

This one scatters in the inflector.

4.2 Muon distance for many events

Can we show how far muons go in various materials?

Let’s collect data for 100 events.

We have a reader that can do n events.

read_file('GeantTrackReaderN.py') %>% cat
from readGallery import GalleryReaderBase  # Necessary for the base class

class GeantStepReaderN(GalleryReaderBase):
  def __init__(self, inputTag, startEvent=100, nEvents=10):
    GalleryReaderBase.__init__(self, inputTag)
    self.names = ['fileEntry', 'eventEntry', 'trackID', 'globalStepNum', 'globalTime', 'totalEnergyDeposit', 
                  'stepLength', 'volumeUID', 
                  'x', 'y', 'z', 'px', 'py', 'pz']
    self.startEvent = startEvent
    self.endEvent   = startEvent + nEvents
    
  def prepare(self, ROOT, ev):
    GalleryReaderBase.prepare(self, ROOT, ev)
    self.getValidHandle = ev.getValidHandle(ROOT.vector(ROOT.gm2ringsim.GeantTrackRecord))

  def fill(self, ROOT, ev):

    # Do we care about this event - if not then don't bother looking
    if ev.eventEntry() < self.startEvent:
      return True
      
    if ev.eventEntry() >= self.endEvent:
      return False

    validHandle = self.getValidHandle(self.inputTag)  # Get the valid handle for gm2ringsim::GeantTrackRecord

    if not validHandle.empty():                       # Does it have data?

      p = validHandle.product()                       # Get the corresponding data product (maybe a vector)

      # Fill from gm2ringsim::GeantStep
      for e in p:                             # Loop over elements and fill
      
        # Get the steps
        for f in e.steps():

          self.vals.append(
            [ ev.fileEntry(), ev.eventEntry(), e.trackID(), f.globalStepNum(), f.globalTime(), 
            f.totalEnergyDeposit(), f.stepLength(), f.volumeUID(), 
            f.pos()[0], f.pos()[1], f.pos()[2], 
            f.p()[0], f.p()[1], f.p()[2] ])

    return True
geantStepReaderNC <- createReaderClass_from_file('GeantTrackReaderN.py')$GeantStepReaderN
geantStepN <- geantStepReaderNC(artInputTag('artg4:KeepStepsAction'), 1000, 1000)
getGalleryData(arrXrdFiles[1], geantStepN)
Opening first file...
Successfully opened file root://fndca1.fnal.gov/pnfs/fnal.gov/usr/GM2/scratch/users/lyon/arr_20170321/15243525_0/ARR_unified_everything_cyl.root
Timings: Overall time = 66.083 s
Time per event: min=0.000   mean=0.030   max=2.367
gsNDF <- galleryReader_df(geantStepN)
gsNDF %>% mutate(fileEntry = 1,
                 p = sqrt(px*px + py*py + pz*pz)) %>%
  inner_join(volNameDF) %>% 
  mutate(volCategory = volName %>% makeVolCategory %>% as.factor)%>% 
  select(volName, volCategory, p, everything()) -> gsNDF
Joining, by = c("fileEntry", "volumeUID")
gsNDF

Let’s do a distribution of distance in the different volumes

gsNDF %>% group_by(eventEntry, volCategory) %>% summarize(
                                                totalDist_meters=round(sum(stepLength)/1000, 2), 
                                                totalELoss_MeV=round(sum(totalEnergyDeposit), 1),
                                                nSteps = n()) -> gsNDFSum
gsNDFSum
gsNDFSum %>% filter(volCategory == 'Ring') %>% 
  ggplot(aes(x=totalDist_meters)) + geom_histogram(bins=50) + 
    labs(x = 'Total distance in Ring material (m)', y='count', title='Muon in Ring Material')

Let’s look at this across the volume categories for energy loss

gsNDFSum %>% ggplot(aes(x=totalELoss_MeV)) + geom_histogram(bins=50) +
  facet_wrap(~volCategory, scales = "free") + 
  labs(x = 'Total energy loss (MeV)', y='count', title='Energy loss in material',
       subtitle = 'Note the different scales')

Let’s get an energy loss curve

gsNDF %>% ggplot(aes(x=p, y=totalEnergyDeposit)) + geom_point() + facet_wrap(~volCategory) + 
  labs(x="Muon Momentum (MeV/c)", y="Total Energy loss (MeV))")

Well, not sure what all this means. Let’s look for a particular event…

gsNDF %>% filter(eventEntry == 1300) %>% ggplot(aes(x=p, y=totalEnergyDeposit)) + geom_point() + facet_wrap(~volCategory) + 
  labs(x="Muon Momentum (MeV/c)", y="Total Energy loss (MeV))", title='Energy loss vs. Momentum for muons in event 1300' )

How many steps do we take?

gsNDFSum %>% ggplot(aes(x=nSteps)) + geom_histogram(bins=50) +
  facet_wrap(~volCategory, scales = "free") + 
  labs(x = 'Number of steps', y='count', title='Number of steps in materials',
       subtitle = 'Note the different scales')

Let’s look at two events

4.2.1 Muon with long distance in iron

gsNDFSum %>% filter(volCategory == 'Ring', totalDist_meters > 3)

Let’s look at event 1758

gsNDF %>% filter(eventEntry == 1758) -> gsNDF1758
gsNDF1758
gsNDF1758 %>% group_by(eventEntry, volCategory) %>% summarize(
                                                totalDist_meters=round(sum(stepLength)/1000, 2), 
                                                totalELoss_MeV=round(sum(totalEnergyDeposit), 1),
                                                nSteps = n()) -> gsNDF1758Sum
gsNDF1758Sum

Let’s plot it!

gsNDF1758 %>% mutate(volCategory = as.factor(as.character(volCategory))) -> gsNDF1758
# lengend3d looks terrible - so do a regular legend
plot(0, type='n', axes=FALSE, ann=FALSE)
with(gsNDF1758,
  legend("bottom", legend=unique(volCategory), col=as.integer(unique(volCategory)), pch=19)
)

clear3d()
with(gsNDF1758,{
     plot3d(x=x, y=y, z=z, type='p', col = as.integer(volCategory), ylim=c(-400, 400), xlim=c(-10000, 10000),
            zlim=c(-10000, 10000))
})
plot3d(ring, add=T, alpha=0.2)
view3d(phi=90, theta=-90)
rglwidget()

Looks like this one started out in a strange place.

4.2.2 Muon with many turns

gsNDFSum %>% filter(volCategory == 'Arc', totalDist_meters > 870)

Let’s try event 1509

gsNDF %>% filter(eventEntry == 1509) -> gsNDF1509
gsNDF1509
gsNDF1509 %>% group_by(eventEntry, volCategory) %>% summarize(
                                                totalDist_meters=round(sum(stepLength)/1000, 2), 
                                                totalELoss_MeV=round(sum(totalEnergyDeposit), 1),
                                                nSteps = n()) -> gsNDF1509Sum
gsNDF1509Sum

Let’s plot it!

gsNDF1509 %>% mutate(volCategory = as.factor(as.character(volCategory))) -> gsNDF1509
# lengend3d looks terrible - so do a regular legend
plot(0, type='n', axes=FALSE, ann=FALSE)
with(gsNDF1509,
  legend("bottom", legend=unique(volCategory), col=as.integer(unique(volCategory)), pch=19)
)

clear3d()
with(gsNDF1509,{
     plot3d(x=x, y=y, z=z, type='p', col = as.integer(volCategory), ylim=c(-400, 400), xlim=c(-10000, 10000),
            zlim=c(-10000, 10000))
})
plot3d(ring, add=T, alpha=0.2)
view3d(phi=90, theta=-90)
rglwidget()

Looks like a nice stored muon!! Can we see CBO?

gsNDF1509 %>% mutate(r = sqrt(x*x+z*z)) -> gsNDF1509
p1 <- gsNDF1509 %>% filter(volCategory %in% c('RngTrkPlane')) %>% ggplot(aes(x=globalTime, y=r)) + geom_line() +
  labs(x='Global time (ns)', y='Radius (mm)', title='Radial CBO', subtitle="Measured by Ring Tracking Planes")
#
p2 <- gsNDF1509 %>% filter(volCategory %in% c('Arc','RngTrkPlane')) %>% ggplot(aes(x=globalTime, y=r)) + 
  geom_line() + 
  labs(x='Global time (ns)', y='Radius (mm)', subtitle="Measured by Arc hits and Ring Tracking Planes")
#
grid.arrange(p1, p2)

We can even see the kick!

Here we’ll plot the points too.

p1 <- gsNDF1509 %>% filter(volCategory %in% c('RngTrkPlane')) %>% ggplot(aes(x=globalTime, y=y)) + geom_line() +
  geom_point() +
  labs(x='Global time (ns)', y='y (mm)', title='Vertical CBO', subtitle="Measured by Ring Tracking Planes")
#
p2 <- gsNDF1509 %>% filter(volCategory %in% c('Arc','RngTrkPlane')) %>% ggplot(aes(x=globalTime, y=y)) + 
  geom_line() + geom_point() + 
  labs(x='Global time (ns)', y='y (mm)', subtitle="Measured by Arc hits and Ring Tracking Planes")
#
grid.arrange(p1, p2)

LS0tCnRpdGxlOiAiRXNjYXBlZCBNdW9ucyIKZGF0ZTogMjAxNy0wMy0yMQphdXRob3I6IEFkYW0gTHlvbgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCi0tLQojIEludHJvZHVjdGlvbiAKClRoZSBnb2FsIG9mIHRoaXMgZG9jdW1lbnQgaXMgdG8gZXhhbWluZSAiZXNjYXBlZCBtdW9ucyIgdGhhdCBkbyBub3QgZGVjYXkgaW4gdGhlIHN0b3JhZ2UgcmVnaW9uIGFuZCBkbyBub3QgZW50ZXIgYSBjYWxvcmltZXRlci4gU29tZSBvZiB0aGVzZSBtdW9ucyBtYXkgbGVhdmUgdGhlIHN0b3JhZ2UgcmluZyBhbHRvZ2V0aGVyLiAKCkkgZ2VuZXJhdGVkIGFydCBmaWxlcyBvZiBzaW11bGF0ZWQgZXZlbnRzIHVzaW5nIGBtZGMyYCB3aXRoIGRpZmZlcmVudCBtYWduZXRpYyBmaWVsZHMgdHVybmVkIG9uIG9yIG9mZiAoc2NlbmFyaW9zKS4gCldlIHdhbnQgdG8gZXhhbWluZSwKCiogTXVvbnMgdGhhdCBhcmUgZWF0ZW4gYnkgdGhlIGlyb24geW9rZSBhbmQgbXVvbnMgdGhhdCBlc2NhcGUgdGhlIHdvcmxkIHZvbHVtZSBlbnRpcmVseS4gCiogV2hlcmUgZG8gbXVvbnMgZXNjYXBlIHRoZSB3b3JsZCAoM0QgYW5kIGhlYXQgbWFwIHBsb3RzPykKKiBDb21wYXJpc29uIG9mIHRoZSBkaWZmZXJlbnQgc2NlbmFyaW9zCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShyZXRpY3VsYXRlKSAgIyBBY2Nlc3MgdG8gcHl0aG9uCmxpYnJhcnkoc3RyaW5ncikgICAjIHN0cmluZyBmdW5jdGlvbnMKbGlicmFyeShwYXJhbGxlbCkgICMgUGFyYWxsZWwgcHJvY2Vzc2luZyAoYnVpbHQtaW4gdG8gUikKbGlicmFyeShkcGx5cikgICAgICMgZGF0YSBhbmFseXNpcwpsaWJyYXJ5KHB1cnJyKSAgICAgIyBGdW5jdGlvbmFsIHByb2dyYW1taW5nCmxpYnJhcnkocmVhZHIpICAgICAjIFJlYWQgZm9ybWF0cwpsaWJyYXJ5KGdncGxvdDIpICAgIyBwbG90aW5nCmxpYnJhcnkocmdsKSAgICAgICAjIDNEIHBsb3RzCmxpYnJhcnkoZ3JpZEV4dHJhKSAjIEFycmFuZ2luZyBwbG90cwpsaWJyYXJ5KHRlc3R0aGF0KSAgIyB0ZXN0aW5nCiMKbGlicmFyeShyZWFkR2FsbGVyeSkgIyBSZWFkIGFydCBHYWxsZXJ5IGZpbGVzCmBgYAoKYGBge3J9CiMgUHV0IGFsbCByZWFkR2FsbGVyeTo6dXNlRGF0YVByb2R1Y3QgY2FsbHMgaGVyZQp1c2VEYXRhUHJvZHVjdCgnc3RkOjp2ZWN0b3I8Z20ydHJ1dGg6OlRyYWNraW5nQWN0aW9uQXJ0UmVjb3JkPicpCnVzZURhdGFQcm9kdWN0KCdzdGQ6OnZlY3RvcjxnbTJyaW5nc2ltOjpHZWFudFRyYWNrUmVjb3JkPicpCmBgYAoKCiMgTG9hZCB0aGUgc2FtcGxlcwoKU2FtcGxlcyBhcmUgbG9jYXRlZCBvbiB0aGUgRmVybWlsYWIgZENhY2hlIGluIHRoZSBkaXJlY3RvcnkgYC9wbmZzL0dNMi9zY3JhdGNoL3VzZXJzL2x5b24vYXJyXzIwMTcwMzIxYC4gCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwcm9wZXJseSBhbHRlciBwYXRocyB0byBhY2NvbW9kYXRlIFhSb290RAojICAgIGUuZy4gY29udmVydCAvcG5mcy9CTEEgLS0+IHJvb3Q6Ly9mbmRjYTEuZm5hbC5nb3YvcG5mcy9mbmFsLmdvdi91c3IvQkxBCnhyb290ZF9pZnkgPC0gZnVuY3Rpb24oYVBhdGgpIHBhc3RlMCgncm9vdDovL2ZuZGNhMS5mbmFsLmdvdi9wbmZzL2ZuYWwuZ292L3VzcicsIHN0cl9yZXBsYWNlKGFQYXRoLCAnL3BuZnMnLCAnJykpCmBgYAoKRGV0ZXJtaW5lIHRoZSBsb2NhdGlvbnMgb2YgdGhlIGRhdGEgZmlsZXMKYGBge3J9CiMgRGV0ZXJtaW5lIGxvY2F0aW9ucyBvZiBvdXIgZmlsZXMKc3lzdGVtKCJzc2ggbHlvbkBnbTJncHZtMDQuZm5hbC5nb3YgJ2xzIC9wbmZzL0dNMi9zY3JhdGNoL3VzZXJzL2x5b24vYXJyXzIwMTcwMzIxLyovKi5yb290JyIsIGludGVybj1UKSAtPiBhcnJGaWxlcwphcnJGaWxlcyAlPiUgeHJvb3RkX2lmeSgpIC0+IGFyclhyZEZpbGVzCmFyclhyZEZpbGVzCmBgYApQdWxsIG91dCB0aGUgc2NlbmFpb3MgKHRoZXNlIHdpbGwgYmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlIGZpbGUgbmFtZXMpCmBgYHtyfQpzY2VuYXJpb3MgPC0gc3RyX21hdGNoKGFyckZpbGVzLCAnYXJyXzIwMTcwMzIxLy4rdW5pZmllZF8oLispX2N5bCcpWywyXQpzY2VuYXJpb3MgJT4lIHVuaXF1ZSgpCmBgYAoKTGV0J3MgbG9vayBhdCB0aGUgY29udGVudHMgb2YgdGhlc2UgZmlsZXMgKHRoZXkncmUgYWxsIHRoZSBzYW1lLCBzbyB3ZSdsbCBqdXN0IGRvIG9uZSkgYGdtMiB2N18wNF8wMGAgd2lsbCBoYXZlIGBwcm9kdWN0X3NpemVzX2R1bXBlcmAuIApgYGB7cn0Kc3RyaW5nVG9SdW4gPC0gc3RyX2ludGVycCgKICAic3NoIGx5b25AZ20yZ3B2bTA0LmZuYWwuZ292ICdzb3VyY2UgL2N2bWZzL2dtMi5vcGVuc2NpZW5jZWdyaWQub3JnL3Byb2Q3L2ctMi9zZXR1cAogICBzZXR1cCBnbTIgdjdfMDRfMDAgLXEgcHJvZiA7IAogICBwcm9kdWN0X3NpemVzX2R1bXBlciAke2FGaWxlfSB8IGdyZXAgOjonIiwgCiAgbGlzdChhRmlsZSA9IGFyckZpbGVzWzFdKQopCiMKc3lzdGVtKHN0cmluZ1RvUnVuKQpgYGAKIyBFc2NhcGluZyBtdW9ucyBmcm9tIHRoZSBUcmFja2luZyBBY3Rpb24gZGF0YQoKVGhlIHRyYWNraW5nIGFjdGlvbiBkYXRhIGhhcyBiaXJ0aCBhbmQgZGVhdGggZGF0YSBmb3IgZXZlcnkgR2VhbnQgdHJhY2suIAoKIyMgTG9hZCBUcmFja2luZyBBY3Rpb24gZGF0YSAKCldlJ2xsIGNhcHR1cmUgdGhpcyBpbmZvcm1hdGlvbiBmb3IgdGhlIHByaW1hcnkgbXVvbiBhbmQgaXRzIGZpcnN0IGdlbmVyYXRpb24gZGF1Z2h0ZXJzLiBTZWUgW2dtMmRhdGFwcm9kdWN0cy9tYy9hY3Rpb25zL3RyYWNrL1RyYWNraW5nQWN0aW9uQXJ0UmVjb3JkLmhoXShodHRwczovL3JlZG1pbmUuZm5hbC5nb3YvcmVkbWluZS9wcm9qZWN0cy9nbTJkYXRhcHJvZHVjdHMvcmVwb3NpdG9yeS9lbnRyeS9tYy9hY3Rpb25zL3RyYWNrL1RyYWNraW5nQWN0aW9uQXJ0UmVjb3JkLmhoP3Jldj1mZWF0dXJlJTJGbWRjMikuIAoKV2UgbmVlZCBhIGByZWFkR2FsbGVyeWAgcmVhZGVyIHB5dGhvbiBjbGFzcy4gR2VuZXJhdGUgd2l0aCwKYGBgcgpyZWFkZXJDbGFzc1NrZWwoJ2dtMnRydXRoOjpUcmFja2luZ0FjdGlvbkFydFJlY29yZCcsIHdyaXRlRmlsZSA9ICd0cmFja2luZ0FjdGlvblJlYWRlci5weScpCmBgYAoKSGVyZSBpcyB0aGUgcmVhZGVyLApgYGB7cn0KcmVhZF9maWxlKCd0cmFja2luZ0FjdGlvblJlYWRlci5weScpICU+JSBjYXQKYGBgCgpNYWtlIHRoZSByZWFkZXIgY2xhc3MgYW5kIG9iamVjdApgYGB7cn0KdHJhY2tpbmdBY3Rpb25SZWFkZXJDIDwtIGNyZWF0ZVJlYWRlckNsYXNzX2Zyb21fZmlsZSgndHJhY2tpbmdBY3Rpb25SZWFkZXIucHknKSRUcmFja2luZ0FjdGlvbkFydFJlY29yZFJlYWRlcgpgYGAKV2UgaGF2ZSBtYW55IGZpbGVzIHRvIHByb2Nlc3MuIExldCdzIGRvIHRoaXMgcmVhZGluZyBpbiBgcGFyYWxsZWxgLiAKCldlIG5lZWQgdG8gY3JlYXRlIGEgcmVhZGVyIG9iamVjdCBwZXIgcGFyYWxsZWwgam9iCmBgYHtyfQp0cmFja2luZ0FjdGlvblJlYWRlcnMgPC0gbWFwKDE6bGVuZ3RoKGFyclhyZEZpbGVzKSwgZnVuY3Rpb24oaSkgdHJhY2tpbmdBY3Rpb25SZWFkZXJDKGFydElucHV0VGFnKCJhcnRnNCIpKSkKYGBgCgpMb2FkIHRoZSBkYXRhCmBgYHtyfQpqb2JzIDwtIGxhcHBseSgxOmxlbmd0aChhcnJYcmRGaWxlcyksIGZ1bmN0aW9uKGkpIGdldEdhbGxlcnlEYXRhKGFyclhyZEZpbGVzW2ldLCB0cmFja2luZ0FjdGlvblJlYWRlcnNbW2ldXSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtY3BhcmFsbGVsKG5hbWU9aSkpCnRyYWNraW5nQWN0aW9uUmV0dXJucyA8LSBtY2NvbGxlY3Qoam9icykKYGBgCgpMZXQncyBtZXJnZSBhbGwgb2YgdGhlIG91dHB1dC4KCmBgYHtyfQp0cmFja2luZ0FjdGlvbkRGIDwtIG1hcF9kZigxOmxlbmd0aCh0cmFja2luZ0FjdGlvblJlYWRlcnMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oaSkgZ2FsbGVyeVJlYWRlcl9kZih0cmFja2luZ0FjdGlvblJlYWRlcnNbW2ldXSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShzY2VuYXJpbz1zY2VuYXJpb3NbaV0sZmlsZUVudHJ5PWkpKQp0cmFja2luZ0FjdGlvbkRGCmBgYApgYGB7cn0KIyBXcml0ZSB0aGlzIG91dCBzbyB3ZSBkb24ndCBuZWVkIHRvIGRvIHRoZSBhYm92ZSBhZ2Fpbgp3cml0ZV9yZHModHJhY2tpbmdBY3Rpb25ERiwgJ3RyYWNraW5nQWN0aW9uREYucmRzJykKYGBgCgpIb3cgbWFueSBtdW9ucyBwZXIgZmlsZT8KYGBge3J9CnRyYWNraW5nQWN0aW9uREYgJT4lIGZpbHRlcih0cmFja0lEPT0xKSAlPiUgZ3JvdXBfYnkoc2NlbmFyaW8sIGZpbGVFbnRyeSkgJT4lIHRhbGx5KCkKYGBgCgojIyMgQWRkIFZvbHVtZSBOYW1lcwoKV2UgbmVlZCB0byB0dXJuIHRoZSB2b2x1bWUgSURzIGludG8gdm9sdW1lIG5hbWVzLiBUaGUgdm9sdW1lIElEcyBjaGFuZ2UgZm9yIGVhY2ggZmlsZS4gV2UgY2FuIHJ1biBhIHNtYWxsIGFydCBqb2IgdG8gZGV0ZXJtaW5lIHRoZSB2b2x1bWUgSUQgdG8gbmFtZSB0YWJsZXMuIAoKYGBge3J9CnJ1bkZvclZvbElEU3RyaW5nIDwtIGZ1bmN0aW9uKGkpIHsKICBzdHJfaW50ZXJwKAogICAgIlBWU19DU1ZPVVQ9JHtjc3ZvdXR9XyR7aX1fdm9sTmFtZXMuY3N2IGdtMiAtYyAke2ZjbFBhdGh9L2dtMmFuYWx5c2VzL2ZjbC9waHlzaWNhbFZvbHVtZVN0b3JlVG9GaWxlLmZjbCAtbiAxICR7YUZpbGV9IiwKICAgIGxpc3QoIGNzdm91dD1zY2VuYXJpb3NbaV0sIGk9aSwgZmNsUGF0aD1TeXMuZ2V0ZW52KCJNUkJfQlVJTERESVIiKSwgYUZpbGU9YXJyWHJkRmlsZXNbaV0pIAogICkKfQpydW5Gb3JWb2xJRFN0cmluZ3MgPC0gc2FwcGx5KDE6bGVuZ3RoKGFyclhyZEZpbGVzKSwgcnVuRm9yVm9sSURTdHJpbmcpCnJ1bkZvclZvbElEU3RyaW5ncwpgYGAKTGV0J3MgcnVuIHRoZSBhcnQgam9icyBpbiBwYXJhbGxlbAoKYGBge3J9CmpvYnMgPC0gbGFwcGx5KDE6bGVuZ3RoKGFyclhyZEZpbGVzKSwgZnVuY3Rpb24oaSkgbWNwYXJhbGxlbChzeXN0ZW0oIHJ1bkZvclZvbElEU3RyaW5nc1tpXSwgaW50ZXJuPVQgKSwgbmFtZT1pKSkKcmVzIDwtIG1jY29sbGVjdChqb2JzKQpgYGAKCmFuZCBsb2FkIHRoZSBDU1YgZmlsZXMuIApgYGB7ciBtZXNzYWdlPUZBTFNFfQpqb2JzIDwtIGxhcHBseSgxOmxlbmd0aChhcnJGaWxlcyksIGZ1bmN0aW9uKGkpIAogIHN0cl9pbnRlcnAoIiR7c2NufV8ke2l9X3ZvbE5hbWVzLmNzdiIsIGxpc3Qoc2NuPXNjZW5hcmlvc1tpXSwgaT1pKSkgJT4lCiAgICByZWFkX2Nzdihjb2xfbmFtZXM9Yygidm9sdW1lVUlEIiwgInZvbE5hbWUiKSkgJT4lIG1jcGFyYWxsZWwobmFtZT1pKSApCiMKdm9sTmFtZVRhYmxlcyA8LSBtY2NvbGxlY3Qoam9icykKdm9sTmFtZURGIDwtIG1hcF9kZigxOmxlbmd0aCh2b2xOYW1lVGFibGVzKSwgZnVuY3Rpb24oaSkgCiAgICAgICAgICAgICAgICAgICAgICB2b2xOYW1lVGFibGVzW1tpXV0gJT4lIG11dGF0ZShzY2VuYXJpbz1zY2VuYXJpb3NbaV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlRW50cnk9aSkpCnZvbE5hbWVERgpgYGAKYGBge3J9CndyaXRlX3Jkcyh2b2xOYW1lREYsICd2b2xOYW1lREYucmRzJykKYGBgCgpOb3cgd2UgbWVyZ2Ugd2l0aCB0aGUgdHJhY2tpbmcgYWN0aW9uIGRhdGEgZnJhbWUKYGBge3J9CnRyYWNraW5nQWN0aW9uREYgJT4lIGlubmVyX2pvaW4odm9sTmFtZURGKSAlPiUgCiAgc2VsZWN0KHNjZW5hcmlvLCBmaWxlRW50cnksIGV2ZW50RW50cnksIHZvbE5hbWUsIGV2ZXJ5dGhpbmcoKSkgLT4gdHJhY2tpbmdBY3Rpb25OREYKdHJhY2tpbmdBY3Rpb25OREYKYGBgCgojIyBIb3cgbWFueSBtdW9ucyBkZWNheSBpbiB0aGUgc3RvcmFnZSByZWdpb24/CgpUaGVzZSBtdW9ucyBkZWNheSBpbiB0aGUgc3RvcmFnZSByZWdpb24gKG5vdCBxdWl0ZSB0aGUgc2FtZSBhcyAic3RvcmVkIiksCmBgYHtyfQp0cmFja2luZ0FjdGlvbk5ERiAlPiUgZmlsdGVyKHRyYWNrSUQ9PTEsIHZvbE5hbWU9PSdBcmNTZWN0aW9uWzAwXScpICU+JSAKICBncm91cF9ieShzY2VuYXJpbywgZmlsZUVudHJ5KSAlPiUgdGFsbHkoKQpgYGAKSW50ZXJlc3RpbmchIFNvLCBmcm9tIHRoaXMsIG9ubHkgYHIgMTE1LzIwMDAwKjEwMGAlIGRlY2F5IGluIHRoZSBzdG9yYWdlIHJlZ2lvbiBmb3IgdGhlICJhbGwgb24iIChvciBldmVyeXRoaW5nKSBzYW1wbGUuIFRoYXQgc2VlbXMgcmF0aGVyIGxvdy4gQnV0IGNvbnRpbnVpbmcuIApgYGB7cn0Kd3JpdGVfcmRzKHRyYWNraW5nQWN0aW9uTkRGLCAndHJhY2tpbmdBY3Rpb25OREYucmRzJykKYGBgCgojIyBXaGVyZSBkbyBtdW9ucyBnbyB0byBkaWU/CgpgYGB7cn0KdHJhY2tpbmdBY3Rpb25OREYgJT4lIGZpbHRlcih0cmFja0lEID09IDEpICU+JSBncm91cF9ieShzY2VuYXJpbywgdm9sTmFtZSkgJT4lIHRhbGx5KCkKYGBgCkl0IG1heSBiZSBuaWNlIHRvIGNhdGVnb3JpemUgdGhlIHZvbHVtZSBuYW1lcyBieSBhcmVhIChlLmcuICJBcmMiLCAiYmVsbG93cyIsICJSaW5nIiwgIkluZmxlY3RvciIpLgoKYGBge3J9CiMgUHVsbCBvdXQgdGhlIGZpcnN0IHdvcmQgaW4gY2FtZWwgY2FzZSAoc2VlIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjk5MTYwNjUvaG93LXRvLWRvLWNhbWVsY2FzZS1zcGxpdC1pbi1weXRob24pCmNhbWVsQ2FzZVNwbGl0IDwtIGZ1bmN0aW9uKHMpIHN0cl9zcGxpdChzLCAnKD88PVthLXpdKSg/PVtBLVpdKXwoPzw9W0EtWl0pKD89W0EtWl1bYS16XSknKQpgYGAKCmBgYHtyfQojIFRlc3QgdGhlIGFib3ZlCmV4cGVjdF9lcXVhbChjYW1lbENhc2VTcGxpdCgiUmluZ1BvbGVUaXBVcHBlciIpW1sxXV0sIGMoIlJpbmciLCAiUG9sZSIsICJUaXAiLCAiVXBwZXIiKSkKZXhwZWN0X2VxdWFsKGNhbWVsQ2FzZVNwbGl0KCJyaW5nUG9sZVRpcFVwcGVyIilbWzFdXSwgYygicmluZyIsICJQb2xlIiwgIlRpcCIsICJVcHBlciIpKQpleHBlY3RfZXF1YWwoY2FtZWxDYXNlU3BsaXQoIndvcmxkIilbWzFdXSwgYygid29ybGQiKSkKZXhwZWN0X2VxdWFsKGNhbWVsQ2FzZVNwbGl0KCJyaW5nUG9sZSIpW1sxXV0sIGMoInJpbmciLCAiUG9sZSIpKQpgYGAKCmBgYHtyfQojIFdlIHJlYWxseSBqdXN0IHdhbnQgdGhlIGZpcnN0IHdvcmQKdGFrZUZpcnN0Q2FtZWwgPC0gZnVuY3Rpb24ocykgY2FtZWxDYXNlU3BsaXQocykgJT4lIG1hcF9jaHIoZnVuY3Rpb24ocykgc1sxXSkKIwojIFRlc3QKdGFrZUZpcnN0Q2FtZWwoIlJpbmdQb2xlVGlwVXBwZXIiKSAlPiUgZXhwZWN0X2VxdWFsKCJSaW5nIikKdGFrZUZpcnN0Q2FtZWwoInJpbmdQb2xlVGlwVXBwZXIiKSAlPiUgZXhwZWN0X2VxdWFsKCJyaW5nIikKdGFrZUZpcnN0Q2FtZWwoIndvcmxkIikgJT4lIGV4cGVjdF9lcXVhbCgid29ybGQiKQp0YWtlRmlyc3RDYW1lbCgicmluZ1BvbGUiKSAlPiUgZXhwZWN0X2VxdWFsKCJyaW5nIikKdGFrZUZpcnN0Q2FtZWwoYygicmluZ1BvbGVUaXBVcHBlciIsICJ3b3JsZCIpKSAlPiUgZXhwZWN0X2VxdWFsKGMoInJpbmciLCAid29ybGQiKSkKYGBgCgpEb24ndCBjb25mdXNlIGBSaW5nVHJhY2tpbmdQbGFuZWAgd2l0aCB0aGUgaXJvbgpgYGB7cn0KbWFrZVZvbENhdGVnb3J5IDwtIGZ1bmN0aW9uKHMpIGlmZWxzZSggc3RyX2RldGVjdChzLCAnUmluZ1RyYWNraW5nJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSbmdUcmtQbGFuZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRha2VGaXJzdENhbWVsKHMpKQpgYGAKYGBge3J9Cm1ha2VWb2xDYXRlZ29yeShjKCJSaW5nQm90dG9tIiwgIlJpbmdUcmFja2luZ1BsYW5lWzhdIiwgIndvcmxkIikpICU+JSBleHBlY3RfZXF1YWwoYygiUmluZyIsICJSbmdUcmtQbGFuZSIsICJ3b3JsZCIpKQpgYGAKCgpgYGB7cn0KdHJhY2tpbmdBY3Rpb25OREYgJT4lIG11dGF0ZSh2b2xDYXRlZ29yeSA9IHZvbE5hbWUgJT4lIG1ha2VWb2xDYXRlZ29yeSgpKSAtPiB0cmFja2luZ0FjdGlvbk5WREYKdHJhY2tpbmdBY3Rpb25OVkRGCmBgYApTaG93IGNvdW50IGJ5IGNhdGVnb3J5CmBgYHtyfQp0cmFja2luZ0FjdGlvbk5WREYgJT4lIGZpbHRlcih0cmFja0lEID09IDEpICU+JSBncm91cF9ieShzY2VuYXJpbywgdm9sQ2F0ZWdvcnkpICU+JSB0YWxseSgpIC0+IHZvbENhdFRhbGx5CnZvbENhdFRhbGx5ICU+JSBtdXRhdGUocGVyYyA9IG4vMjAwMDAgKiAxMDApIC0+IHZvbENhdFRhbGx5CnZvbENhdFRhbGx5CmBgYApMZXQncyBwbG90IQpgYGB7cn0KdHJhY2tpbmdBY3Rpb25OVkRGICU+JSBmaWx0ZXIodHJhY2tJRCA9PTEpICU+JSBnZ3Bsb3QoYWVzKHg9dm9sQ2F0ZWdvcnksIGdyb3VwPXNjZW5hcmlvKSkgKyAKICBnZW9tX2JhcigpCmBgYApgYGB7cn0KZ2dwbG90KHZvbENhdFRhbGx5LCBhZXMoeCA9IHZvbENhdGVnb3J5LCB5PXBlcmMsIGZpbGw9c2NlbmFyaW8pKSArIAogIGdlb21fYmFyKHN0YXQ9IklkZW50aXR5Iiwgd2lkdGg9MC41LCBwb3NpdGlvbj0iZG9kZ2UiKQpgYGAKQ2FuJ3QgcmVhbGx5IHNlZSBub24tUmluZy93b3JsZCBvbmVzLiAgTGV0J3Mgc3BsaXQgdGhlbSBvdXQuCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBtYWtlIHRoaXMgZWFzeQpwbG90aXQgPC0gZnVuY3Rpb24oZCkgZ2dwbG90KGQsIGFlcyh4ID0gdm9sQ2F0ZWdvcnksIHk9cGVyYywgZmlsbD1zY2VuYXJpbykgKSArIAogIGdlb21fYmFyKHN0YXQ9IklkZW50aXR5Iiwgd2lkdGg9MC41LCBwb3NpdGlvbj0iZG9kZ2UiKSArIAogIHhsYWIoIlZvbHVtZSBjYXRlZ29yeSIpICsgeWxhYigiUGVyY2VudCIpCgp2b2xDYXRUYWxseSAlPiUgZmlsdGVyKHZvbENhdGVnb3J5ICVpbiUgYygiUmluZyIsICJ3b3JsZCIpKSAlPiUgcGxvdGl0IC0+IHAxCgp2b2xDYXRUYWxseSAlPiUgZmlsdGVyKCEgdm9sQ2F0ZWdvcnkgJWluJSBjKCJSaW5nIiwgIndvcmxkIikpICU+JSBwbG90aXQgLT4gcDIKCmdyaWQuYXJyYW5nZShwMSwgcDIpCmBgYApMZXQncyBzZWUgd2hlcmUgdGhleSBkaWUKYGBge3J9CiMgU2VlIGh0dHBzOi8vcnB1YnMuY29tL2hhZGxleS85Nzk3MCBmb3IgaG93IHRvIHdyYXAgYSBtdWx0aXBhcnQgZ2dwbG90MiBjb21wb25lbnQKcGxvdENvbW1vbiA8LSBmdW5jdGlvbiAoKSB7CiAgbGlzdCgKICAgIGZhY2V0X3dyYXAofnNjZW5hcmlvKSwKICAgIGd1aWRlcyhjb2wgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTUsIGFscGhhPTEpKSksCiAgICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lPSJWb2x1bWVcbkNhdGVnb3J5IiksCiAgICBsYWJzKHg9InogKG1tKSIsIHk9InggKG1tKSIpLAogICAgdGhlbWVfbWluaW1hbCgpCiAgKQp9CmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9OH0KdHJhY2tpbmdBY3Rpb25OVkRGICU+JSBmaWx0ZXIodHJhY2tJRCA9PSAxKSAlPiUgCiAgZ2dwbG90KCBhZXMoeD16LCB5PXgsIGNvbG9yPXZvbENhdGVnb3J5KSkgKyAKICAgIGdlb21fcG9pbnQoYWxwaGE9MC4xKSArIAogICAgZ2d0aXRsZSgnV2hlcmUgTXVvbnMgRGllJykgKwogICAgcGxvdENvbW1vbigpCmBgYApIZXJlIGl0IGlzIHdpdGhvdXQgdGhlIHJpbmcgbG9zc2VzLCB3aGljaCBkb21pbmF0ZQpgYGB7ciBmaWcuaGVpZ2h0PTh9CnRyYWNraW5nQWN0aW9uTlZERiAlPiUgZmlsdGVyKHRyYWNrSUQgPT0gMSwgdm9sQ2F0ZWdvcnkgIT0gJ1JpbmcnKSAlPiUgCiAgZ2dwbG90KCBhZXMoeD16LCB5PXgsIGNvbG9yPXZvbENhdGVnb3J5KSkgKyAKICAgIGdlb21fcG9pbnQoYWxwaGE9MC41KSArIAogICAgZ2d0aXRsZSgiV2hlcmUgTXVvbnMgRGllIiwgc3VidGl0bGUgPSAiUmluZyBlc2NhcGVlcyBleGNsdWRlZCBmb3IgY2xhcml0eSIpICsKICAgIHBsb3RDb21tb24oKQpgYGAKCiMjIERvZXMgaXQgbWFrZSBzZW5zZSBmb3Igc28gbWFueSBtdW9ucyB0byBzdG9wIGluIHRoZSBpcm9uPwoKV2UgaGF2ZSAzIEdlViBtdW9ucy4gRG9lcyBpdCBtYWtlIHNlbnNlIHRoYXQgdGhlIHZhc3QgbWFqb3JpdHkgb2YgdGhlbSBzdG9wIGluIHRoZSBpcm9uPyBBIFt0YWJsZV0oaHR0cDovL3BkZy5sYmwuZ292LzIwMTYvQXRvbWljTnVjbGVhclByb3BlcnRpZXMvTVVFL211RV9pcm9uX0ZlLnBkZikgc2hvd3MgdGhlIENvbnRpbnVvdXMgU2xvdyBEb3duIEFwcHJveGltYXRpb24gcmFuZ2Ugb2YgbXVvbnMgKENTREEpLiBGb3IgYSAzIEdlViBtdW9uIGluIGlyb24sIHRoZSBDU0RBIGlzICQxLjgyNSBcdGltZXMgMTBeezN9JCBnL2NtJF4yJC4gVGhlIGRlbnNpdHkgJFxyaG8kIGlzIDcuODc0IGcvY20kXjMkLiBTbywgd2hlcmUgJFIkIGlzIHJhbmdlLCAKCiQkUiA9IFx0ZXh0e0NTREF9L1xyaG8kJApSYW5nZSBpcyB0aHVzIGByIHJvdW5kKDE4MjUvNy44NzQvMTAwLCAyKWAgbS4gVGhpcyBpcyBiZWdnZXIgdGhhbiB0aGUgd2lkdGggb2YgdGhlIGlyb24sIGJ1dCByZW1lbWJlciB0aGF0IHRoZSBtdW9ucyBjb21lIGluIGF0IGFuIG9ibGlxdWUgYW5nbGUuIFdlJ2xsIGhhdmUgdG8gcHJvdmUgdGhpcy4gCgojIEhvdyBmYXIgZG8gbXVvbnMgZ28gaW4gdGhlIGlyb24/CgpXZSBoYXZlIHRoZSBHZWFudCBzdGVwcGluZyBpbmZvcm1hdGlvbiwgc28gd2Ugc2hvdWxkIGJlIGFibGUgdG8gZmlndXJlIG91dCBob3cgZmFyIHRoZSBtdW9ucyBnbyBpbiB0aGUgaXJvbi4gCgpIZXJlIGlzIHRoZSBHYWxsZXJ5IHJlYWRlciwKYGBge3J9CnJlYWRfZmlsZSgnR2VhbnRUcmFja1JlYWRlci5weScpICU+JSBjYXQKYGBgCmBgYHtyfQpnZWFudFN0ZXBSZWFkZXJDIDwtIGNyZWF0ZVJlYWRlckNsYXNzX2Zyb21fZmlsZSgnR2VhbnRUcmFja1JlYWRlci5weScpJEdlYW50U3RlcFJlYWRlcgpgYGAKCiMjIE11b24gZGlzdGFuY2UgaW4gaXJvbiBmb3Igb25lIGV2ZW50CgpMZXQncyBmaW5kIGFuIGV2ZW50IHdoZXJlIHRoZSBtdW9uIGRpZCBpbiB0aGUgaXJvbi4gCgpgYGB7cn0KdHJhY2tpbmdBY3Rpb25OVkRGICU+JSBmaWx0ZXIodHJhY2tJRCA9PSAxLCB2b2xOYW1lID09ICdSaW5nWW9rZUJvdHRvbScpCmBgYApFdmVudCA0IGxvb2tzIGdvb2QuIAoKYGBge3J9CmdlYW50U3RlcE9uZSA8LSBnZWFudFN0ZXBSZWFkZXJDKGFydElucHV0VGFnKCdhcnRnNDpLZWVwU3RlcHNBY3Rpb24nKSwgdHVwbGUoYXMuaW50ZWdlcig0KSkpCmBgYApgYGB7cn0KZ2V0R2FsbGVyeURhdGEoYXJyWHJkRmlsZXNbMV0sIGdlYW50U3RlcE9uZSkKYGBgCmBgYHtyfQpnc09uZURGIDwtIGdhbGxlcnlSZWFkZXJfZGYoZ2VhbnRTdGVwT25lKQpgYGAKCk1lcmdlIGluIHZvbHVtZSBuYW1lcwpgYGB7cn0KZ3NPbmVERiAlPiUgbXV0YXRlKGZpbGVFbnRyeSA9IDEpICU+JQogIGlubmVyX2pvaW4odm9sTmFtZURGKSAlPiUgCiAgc2VsZWN0KHZvbE5hbWUsIGV2ZXJ5dGhpbmcoKSkgLT4gZ3NPbmVERgpnc09uZURGCmBgYApMZXQncyBtYWtlIGEgM0QgcGxvdCBvZiB0aGlzIHBhdGgKCmBgYHtyfQpyaW5nIDwtIGN5bGluZGVyM2QoIGNlbnRlcj1yYmluZChjKDAsLTkwLCAwKSwgYygwLDkwLDApKSwKICAgICAgICAgICAgICAgICAgICByYWRpdXM9NzExMiwKICAgICAgICAgICAgICAgICAgICBzaWRlcz0yMCwgY2xvc2VkID0gRikKYGBgCgpMZXQncyBkbyB2b2x1bWUgY2F0ZWdvcmllcyBhZ2Fpbi4KYGBge3J9CmdzT25lREYgJT4lIG11dGF0ZSh2b2xDYXRlZ29yeSA9IHZvbE5hbWUgJT4lIG1ha2VWb2xDYXRlZ29yeSAlPiUgYXMuZmFjdG9yKSAtPiBnc09uZURGCmBgYAoKTGV0J3MgcGxvdCB0aGUgcGF0aC4gTm90ZSB0aGF0IEkgaGF2ZSB0byBtYWtlIHRoZSBsZWdlbmQgc2VwYXJhdGVseSBzaW5jZSBgbGVnZW5kM2RgIGxvb2tzIGF3ZnVsLiAKYGBge3IgZmlnLndpZHRoPTV9CiMgbGVuZ2VuZDNkIGxvb2tzIHRlcnJpYmxlIC0gc28gZG8gYSByZWd1bGFyIGxlZ2VuZApwbG90KDEsIHR5cGU9J24nLCBheGVzPUZBTFNFLCBhbm49RkFMU0UpCndpdGgoZ3NPbmVERiwKICBsZWdlbmQoInRvcCIsIGxlZ2VuZD11bmlxdWUodm9sQ2F0ZWdvcnkpLCBjb2w9YXMuaW50ZWdlcih1bmlxdWUodm9sQ2F0ZWdvcnkpKSwgcGNoPTE5KQopCmBgYApgYGB7ciBmaWcud2lkdGg9OH0KY2xlYXIzZCgpCndpdGgoZ3NPbmVERix7CiAgICAgcGxvdDNkKHg9eCwgeT15LCB6PXosIHR5cGU9J3AnLCBjb2wgPSBhcy5pbnRlZ2VyKHZvbENhdGVnb3J5KSwgeWxpbT1jKC00MDAsIDQwMCkpCn0pCnBsb3QzZChyaW5nLCBhZGQ9VCwgYWxwaGE9MC4yKQoKdmlldzNkKHBoaT05MCwgdGhldGE9LTkwKQpyZ2x3aWRnZXQoKQpgYGAKSG93IG11Y2ggZW5lcmd5IGxvc3MgYW5kIGRpc3RhbmNlIHRyYXZlbGVkIGluIGVhY2ggdm9sdW1lIGNhdGVnb3J5CmBgYHtyfQpnc09uZURGICU+JSBncm91cF9ieSh2b2xDYXRlZ29yeSkgJT4lIHN1bW1hcml6ZSh0b3RhbERpc3RfbWV0ZXJzPXJvdW5kKHN1bShzdGVwTGVuZ3RoKS8xMDAwLCAyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsRUxvc3NfTWVWPXJvdW5kKHN1bSh0b3RhbEVuZXJneURlcG9zaXQpLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgblN0ZXBzID0gbigpKQpgYGAKT2sgLSBJIGJlbGlldmUgdGhpcyAobm90ZSB0aGF0IHRoZSB5IHNjYWxlIGlzIHZlcnkgc21hbGwgY29tcGFyZWQgdG8gdGhlIHgseiBzY2FsZXMgLSBzbyB0aGUgbXVvbiBhY3V0YWxseSB0cmF2ZWxzIHF1aXRlIGZhciBpbiB4ICYgeikuIFRoZSBtdW9uIHRyYXZlbHMgYWJvdXQgMi40bSBpbiB0aGUgaXJvbiBhbmQgcmFuZ2VzIG91dC4gUGh5c2ljcyAoYW5kIEdlYW50KSB3b3JrIQoKTGV0J3MgdHJ5IGFub3RoZXIgb25lCmBgYHtyfQpnZWFudFN0ZXBPbmVBIDwtIGdlYW50U3RlcFJlYWRlckMoYXJ0SW5wdXRUYWcoJ2FydGc0OktlZXBTdGVwc0FjdGlvbicpLCB0dXBsZShhcy5pbnRlZ2VyKDEwKSkpCmBgYAoKYGBge3J9CmdldEdhbGxlcnlEYXRhKGFyclhyZEZpbGVzWzFdLCBnZWFudFN0ZXBPbmVBKQpgYGAKCmBgYHtyfQpnc09uZUFERiA8LSBnYWxsZXJ5UmVhZGVyX2RmKGdlYW50U3RlcE9uZUEpCmdzT25lQURGICU+JSBtdXRhdGUoZmlsZUVudHJ5ID0gMSkgJT4lCiAgaW5uZXJfam9pbih2b2xOYW1lREYpICU+JSAKICBtdXRhdGUodm9sQ2F0ZWdvcnkgPSB2b2xOYW1lICU+JSBtYWtlVm9sQ2F0ZWdvcnkgJT4lIGFzLmZhY3RvciklPiUgCiAgc2VsZWN0KHZvbE5hbWUsIHZvbENhdGVnb3J5LCBldmVyeXRoaW5nKCkpIC0+IGdzT25lQURGCmdzT25lQURGCmBgYApgYGB7cn0KZ3NPbmVBREYgJT4lIGdyb3VwX2J5KHZvbENhdGVnb3J5KSAlPiUgc3VtbWFyaXplKHRvdGFsRGlzdF9tZXRlcnM9cm91bmQoc3VtKHN0ZXBMZW5ndGgpLzEwMDAsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxFTG9zc19NZVY9cm91bmQoc3VtKHRvdGFsRW5lcmd5RGVwb3NpdCksIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuU3RlcHMgPSBuKCkpIC0+IGdzT25lQURGU3VtCmdzT25lQURGU3VtCmBgYApDaGVjayBzdW1zCmBgYHtyfQpnc09uZUFERlN1bSAlPiUgc3VtbWFyaXplKHN1bSh0b3RhbEVMb3NzX01lVikpCmBgYApgYGB7cn0KZ3NPbmVBREYgJT4lIHN1bW1hcml6ZShzdW0odG90YWxFbmVyZ3lEZXBvc2l0KSkKYGBgCgoKYGBge3J9CiMgbGVuZ2VuZDNkIGxvb2tzIHRlcnJpYmxlIC0gc28gZG8gYSByZWd1bGFyIGxlZ2VuZApwbG90KDEsIHR5cGU9J24nLCBheGVzPUZBTFNFLCBhbm49RkFMU0UpCndpdGgoZ3NPbmVBREYsCiAgbGVnZW5kKCJ0b3AiLCBsZWdlbmQ9dW5pcXVlKHZvbENhdGVnb3J5KSwgY29sPWFzLmludGVnZXIodW5pcXVlKHZvbENhdGVnb3J5KSksIHBjaD0xOSkKKQpgYGAKCmBgYHtyfQpjbGVhcjNkKCkKd2l0aChnc09uZUFERix7CiAgICAgcGxvdDNkKHg9eCwgeT15LCB6PXosIHR5cGU9J3AnLCBjb2wgPSBhcy5pbnRlZ2VyKHZvbENhdGVnb3J5KSwgeWxpbT1jKC00MDAsIDQwMCksIHhsaW09YygtMTAwMDAsIDEwMDAwKSwKICAgICAgICAgICAgemxpbT1jKC0xMDAwMCwgMTAwMDApKQp9KQpwbG90M2QocmluZywgYWRkPVQsIGFscGhhPTAuMikKCnZpZXczZChwaGk9OTAsIHRoZXRhPS05MCkKcmdsd2lkZ2V0KCkKYGBgClRoaXMgb25lIHNjYXR0ZXJzIGluIHRoZSBpbmZsZWN0b3IuIAoKIyMgTXVvbiBkaXN0YW5jZSBmb3IgbWFueSBldmVudHMKCkNhbiB3ZSBzaG93IGhvdyBmYXIgbXVvbnMgZ28gaW4gdmFyaW91cyBtYXRlcmlhbHM/CgpMZXQncyBjb2xsZWN0IGRhdGEgZm9yIDEwMCBldmVudHMuCgpXZSBoYXZlIGEgcmVhZGVyIHRoYXQgY2FuIGRvICpuKiBldmVudHMuCmBgYHtyfQpyZWFkX2ZpbGUoJ0dlYW50VHJhY2tSZWFkZXJOLnB5JykgJT4lIGNhdApgYGAKYGBge3J9CmdlYW50U3RlcFJlYWRlck5DIDwtIGNyZWF0ZVJlYWRlckNsYXNzX2Zyb21fZmlsZSgnR2VhbnRUcmFja1JlYWRlck4ucHknKSRHZWFudFN0ZXBSZWFkZXJOCmBgYApgYGB7cn0KZ2VhbnRTdGVwTiA8LSBnZWFudFN0ZXBSZWFkZXJOQyhhcnRJbnB1dFRhZygnYXJ0ZzQ6S2VlcFN0ZXBzQWN0aW9uJyksIDEwMDAsIDEwMDApCmBgYAoKYGBge3J9CmdldEdhbGxlcnlEYXRhKGFyclhyZEZpbGVzWzFdLCBnZWFudFN0ZXBOKQpgYGAKYGBge3J9CmdzTkRGIDwtIGdhbGxlcnlSZWFkZXJfZGYoZ2VhbnRTdGVwTikKZ3NOREYgJT4lIG11dGF0ZShmaWxlRW50cnkgPSAxLAogICAgICAgICAgICAgICAgIHAgPSBzcXJ0KHB4KnB4ICsgcHkqcHkgKyBweipweikpICU+JQogIGlubmVyX2pvaW4odm9sTmFtZURGKSAlPiUgCiAgbXV0YXRlKHZvbENhdGVnb3J5ID0gdm9sTmFtZSAlPiUgbWFrZVZvbENhdGVnb3J5ICU+JSBhcy5mYWN0b3IpJT4lIAogIHNlbGVjdCh2b2xOYW1lLCB2b2xDYXRlZ29yeSwgcCwgZXZlcnl0aGluZygpKSAtPiBnc05ERgpnc05ERgpgYGAKTGV0J3MgZG8gYSBkaXN0cmlidXRpb24gb2YgZGlzdGFuY2UgaW4gdGhlIGRpZmZlcmVudCB2b2x1bWVzCmBgYHtyfQpnc05ERiAlPiUgZ3JvdXBfYnkoZXZlbnRFbnRyeSwgdm9sQ2F0ZWdvcnkpICU+JSBzdW1tYXJpemUoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsRGlzdF9tZXRlcnM9cm91bmQoc3VtKHN0ZXBMZW5ndGgpLzEwMDAsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxFTG9zc19NZVY9cm91bmQoc3VtKHRvdGFsRW5lcmd5RGVwb3NpdCksIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuU3RlcHMgPSBuKCkpIC0+IGdzTkRGU3VtCmdzTkRGU3VtCmBgYAoKYGBge3J9CmdzTkRGU3VtICU+JSBmaWx0ZXIodm9sQ2F0ZWdvcnkgPT0gJ1JpbmcnKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXRvdGFsRGlzdF9tZXRlcnMpKSArIGdlb21faGlzdG9ncmFtKGJpbnM9NTApICsgCiAgICBsYWJzKHggPSAnVG90YWwgZGlzdGFuY2UgaW4gUmluZyBtYXRlcmlhbCAobSknLCB5PSdjb3VudCcsIHRpdGxlPSdNdW9uIGluIFJpbmcgTWF0ZXJpYWwnKQpgYGAKIExldCdzIGxvb2sgYXQgdGhpcyBhY3Jvc3MgdGhlIHZvbHVtZSBjYXRlZ29yaWVzIGZvciBlbmVyZ3kgbG9zcwogCmBgYHtyfQpnc05ERlN1bSAlPiUgZ2dwbG90KGFlcyh4PXRvdGFsRUxvc3NfTWVWKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zPTUwKSArCiAgZmFjZXRfd3JhcCh+dm9sQ2F0ZWdvcnksIHNjYWxlcyA9ICJmcmVlIikgKyAKICBsYWJzKHggPSAnVG90YWwgZW5lcmd5IGxvc3MgKE1lViknLCB5PSdjb3VudCcsIHRpdGxlPSdFbmVyZ3kgbG9zcyBpbiBtYXRlcmlhbCcsCiAgICAgICBzdWJ0aXRsZSA9ICdOb3RlIHRoZSBkaWZmZXJlbnQgc2NhbGVzJykKYGBgCkxldCdzIGdldCBhbiBlbmVyZ3kgbG9zcyBjdXJ2ZQpgYGB7cn0KZ3NOREYgJT4lIGdncGxvdChhZXMoeD1wLCB5PXRvdGFsRW5lcmd5RGVwb3NpdCkpICsgZ2VvbV9wb2ludCgpICsgZmFjZXRfd3JhcCh+dm9sQ2F0ZWdvcnkpICsgCiAgbGFicyh4PSJNdW9uIE1vbWVudHVtIChNZVYvYykiLCB5PSJUb3RhbCBFbmVyZ3kgbG9zcyAoTWVWKSkiKQpgYGAKV2VsbCwgbm90IHN1cmUgd2hhdCBhbGwgdGhpcyBtZWFucy4gTGV0J3MgbG9vayBmb3IgYSBwYXJ0aWN1bGFyIGV2ZW50Li4uCmBgYHtyfQpnc05ERiAlPiUgZmlsdGVyKGV2ZW50RW50cnkgPT0gMTMwMCkgJT4lIGdncGxvdChhZXMoeD1wLCB5PXRvdGFsRW5lcmd5RGVwb3NpdCkpICsgZ2VvbV9wb2ludCgpICsgZmFjZXRfd3JhcCh+dm9sQ2F0ZWdvcnkpICsgCiAgbGFicyh4PSJNdW9uIE1vbWVudHVtIChNZVYvYykiLCB5PSJUb3RhbCBFbmVyZ3kgbG9zcyAoTWVWKSkiLCB0aXRsZT0nRW5lcmd5IGxvc3MgdnMuIE1vbWVudHVtIGZvciBtdW9ucyBpbiBldmVudCAxMzAwJyApCmBgYApIb3cgbWFueSBzdGVwcyBkbyB3ZSB0YWtlPwpgYGB7cn0KZ3NOREZTdW0gJT4lIGdncGxvdChhZXMoeD1uU3RlcHMpKSArIGdlb21faGlzdG9ncmFtKGJpbnM9NTApICsKICBmYWNldF93cmFwKH52b2xDYXRlZ29yeSwgc2NhbGVzID0gImZyZWUiKSArIAogIGxhYnMoeCA9ICdOdW1iZXIgb2Ygc3RlcHMnLCB5PSdjb3VudCcsIHRpdGxlPSdOdW1iZXIgb2Ygc3RlcHMgaW4gbWF0ZXJpYWxzJywKICAgICAgIHN1YnRpdGxlID0gJ05vdGUgdGhlIGRpZmZlcmVudCBzY2FsZXMnKQpgYGAKCkxldCdzIGxvb2sgYXQgdHdvIGV2ZW50cwoKIyMjIE11b24gd2l0aCBsb25nIGRpc3RhbmNlIGluIGlyb24KCmBgYHtyfQpnc05ERlN1bSAlPiUgZmlsdGVyKHZvbENhdGVnb3J5ID09ICdSaW5nJywgdG90YWxEaXN0X21ldGVycyA+IDMpCmBgYApMZXQncyBsb29rIGF0IGV2ZW50IDE3NTgKYGBge3J9CmdzTkRGICU+JSBmaWx0ZXIoZXZlbnRFbnRyeSA9PSAxNzU4KSAtPiBnc05ERjE3NTgKZ3NOREYxNzU4CmBgYApgYGB7cn0KZ3NOREYxNzU4ICU+JSBncm91cF9ieShldmVudEVudHJ5LCB2b2xDYXRlZ29yeSkgJT4lIHN1bW1hcml6ZSgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxEaXN0X21ldGVycz1yb3VuZChzdW0oc3RlcExlbmd0aCkvMTAwMCwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbEVMb3NzX01lVj1yb3VuZChzdW0odG90YWxFbmVyZ3lEZXBvc2l0KSwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5TdGVwcyA9IG4oKSkgLT4gZ3NOREYxNzU4U3VtCmdzTkRGMTc1OFN1bQpgYGAKTGV0J3MgcGxvdCBpdCEKCmBgYHtyfQpnc05ERjE3NTggJT4lIG11dGF0ZSh2b2xDYXRlZ29yeSA9IGFzLmZhY3Rvcihhcy5jaGFyYWN0ZXIodm9sQ2F0ZWdvcnkpKSkgLT4gZ3NOREYxNzU4CmBgYAoKCmBgYHtyfQojIGxlbmdlbmQzZCBsb29rcyB0ZXJyaWJsZSAtIHNvIGRvIGEgcmVndWxhciBsZWdlbmQKcGxvdCgwLCB0eXBlPSduJywgYXhlcz1GQUxTRSwgYW5uPUZBTFNFKQp3aXRoKGdzTkRGMTc1OCwKICBsZWdlbmQoImJvdHRvbSIsIGxlZ2VuZD11bmlxdWUodm9sQ2F0ZWdvcnkpLCBjb2w9YXMuaW50ZWdlcih1bmlxdWUodm9sQ2F0ZWdvcnkpKSwgcGNoPTE5KQopCmBgYAoKYGBge3J9CmNsZWFyM2QoKQp3aXRoKGdzTkRGMTc1OCx7CiAgICAgcGxvdDNkKHg9eCwgeT15LCB6PXosIHR5cGU9J3AnLCBjb2wgPSBhcy5pbnRlZ2VyKHZvbENhdGVnb3J5KSwgeWxpbT1jKC00MDAsIDQwMCksIHhsaW09YygtMTAwMDAsIDEwMDAwKSwKICAgICAgICAgICAgemxpbT1jKC0xMDAwMCwgMTAwMDApKQp9KQpwbG90M2QocmluZywgYWRkPVQsIGFscGhhPTAuMikKdmlldzNkKHBoaT05MCwgdGhldGE9LTkwKQpyZ2x3aWRnZXQoKQpgYGAKTG9va3MgbGlrZSB0aGlzIG9uZSBzdGFydGVkIG91dCBpbiBhIHN0cmFuZ2UgcGxhY2UuIAoKIyMjIE11b24gd2l0aCBtYW55IHR1cm5zCgpgYGB7cn0KZ3NOREZTdW0gJT4lIGZpbHRlcih2b2xDYXRlZ29yeSA9PSAnQXJjJywgdG90YWxEaXN0X21ldGVycyA+IDg3MCkKYGBgCkxldCdzIHRyeSBldmVudCAxNTA5CgpgYGB7cn0KZ3NOREYgJT4lIGZpbHRlcihldmVudEVudHJ5ID09IDE1MDkpIC0+IGdzTkRGMTUwOQpnc05ERjE1MDkKYGBgCmBgYHtyfQpnc05ERjE1MDkgJT4lIGdyb3VwX2J5KGV2ZW50RW50cnksIHZvbENhdGVnb3J5KSAlPiUgc3VtbWFyaXplKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbERpc3RfbWV0ZXJzPXJvdW5kKHN1bShzdGVwTGVuZ3RoKS8xMDAwLCAyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsRUxvc3NfTWVWPXJvdW5kKHN1bSh0b3RhbEVuZXJneURlcG9zaXQpLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgblN0ZXBzID0gbigpKSAtPiBnc05ERjE1MDlTdW0KZ3NOREYxNTA5U3VtCmBgYApMZXQncyBwbG90IGl0IQoKYGBge3J9CmdzTkRGMTUwOSAlPiUgbXV0YXRlKHZvbENhdGVnb3J5ID0gYXMuZmFjdG9yKGFzLmNoYXJhY3Rlcih2b2xDYXRlZ29yeSkpKSAtPiBnc05ERjE1MDkKYGBgCgoKYGBge3J9CiMgbGVuZ2VuZDNkIGxvb2tzIHRlcnJpYmxlIC0gc28gZG8gYSByZWd1bGFyIGxlZ2VuZApwbG90KDAsIHR5cGU9J24nLCBheGVzPUZBTFNFLCBhbm49RkFMU0UpCndpdGgoZ3NOREYxNTA5LAogIGxlZ2VuZCgiYm90dG9tIiwgbGVnZW5kPXVuaXF1ZSh2b2xDYXRlZ29yeSksIGNvbD1hcy5pbnRlZ2VyKHVuaXF1ZSh2b2xDYXRlZ29yeSkpLCBwY2g9MTkpCikKYGBgCgpgYGB7cn0KY2xlYXIzZCgpCndpdGgoZ3NOREYxNTA5LHsKICAgICBwbG90M2QoeD14LCB5PXksIHo9eiwgdHlwZT0ncCcsIGNvbCA9IGFzLmludGVnZXIodm9sQ2F0ZWdvcnkpLCB5bGltPWMoLTQwMCwgNDAwKSwgeGxpbT1jKC0xMDAwMCwgMTAwMDApLAogICAgICAgICAgICB6bGltPWMoLTEwMDAwLCAxMDAwMCkpCn0pCnBsb3QzZChyaW5nLCBhZGQ9VCwgYWxwaGE9MC4yKQp2aWV3M2QocGhpPTkwLCB0aGV0YT0tOTApCnJnbHdpZGdldCgpCmBgYApMb29rcyBsaWtlIGEgbmljZSBzdG9yZWQgbXVvbiEhIENhbiB3ZSBzZWUgQ0JPPwoKYGBge3J9CmdzTkRGMTUwOSAlPiUgbXV0YXRlKHIgPSBzcXJ0KHgqeCt6KnopKSAtPiBnc05ERjE1MDkKYGBgCgpgYGB7cn0KcDEgPC0gZ3NOREYxNTA5ICU+JSBmaWx0ZXIodm9sQ2F0ZWdvcnkgJWluJSBjKCdSbmdUcmtQbGFuZScpKSAlPiUgZ2dwbG90KGFlcyh4PWdsb2JhbFRpbWUsIHk9cikpICsgZ2VvbV9saW5lKCkgKwogIGxhYnMoeD0nR2xvYmFsIHRpbWUgKG5zKScsIHk9J1JhZGl1cyAobW0pJywgdGl0bGU9J1JhZGlhbCBDQk8nLCBzdWJ0aXRsZT0iTWVhc3VyZWQgYnkgUmluZyBUcmFja2luZyBQbGFuZXMiKQojCnAyIDwtIGdzTkRGMTUwOSAlPiUgZmlsdGVyKHZvbENhdGVnb3J5ICVpbiUgYygnQXJjJywnUm5nVHJrUGxhbmUnKSkgJT4lIGdncGxvdChhZXMoeD1nbG9iYWxUaW1lLCB5PXIpKSArIAogIGdlb21fbGluZSgpICsgCiAgbGFicyh4PSdHbG9iYWwgdGltZSAobnMpJywgeT0nUmFkaXVzIChtbSknLCBzdWJ0aXRsZT0iTWVhc3VyZWQgYnkgQXJjIGhpdHMgYW5kIFJpbmcgVHJhY2tpbmcgUGxhbmVzIikKIwpncmlkLmFycmFuZ2UocDEsIHAyKQpgYGAKV2UgY2FuIGV2ZW4gc2VlIHRoZSBraWNrIQoKSGVyZSB3ZSdsbCBwbG90IHRoZSBwb2ludHMgdG9vLiAKYGBge3J9CnAxIDwtIGdzTkRGMTUwOSAlPiUgZmlsdGVyKHZvbENhdGVnb3J5ICVpbiUgYygnUm5nVHJrUGxhbmUnKSkgJT4lIGdncGxvdChhZXMoeD1nbG9iYWxUaW1lLCB5PXkpKSArIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnMoeD0nR2xvYmFsIHRpbWUgKG5zKScsIHk9J3kgKG1tKScsIHRpdGxlPSdWZXJ0aWNhbCBDQk8nLCBzdWJ0aXRsZT0iTWVhc3VyZWQgYnkgUmluZyBUcmFja2luZyBQbGFuZXMiKQojCnAyIDwtIGdzTkRGMTUwOSAlPiUgZmlsdGVyKHZvbENhdGVnb3J5ICVpbiUgYygnQXJjJywnUm5nVHJrUGxhbmUnKSkgJT4lIGdncGxvdChhZXMoeD1nbG9iYWxUaW1lLCB5PXkpKSArIAogIGdlb21fbGluZSgpICsgZ2VvbV9wb2ludCgpICsgCiAgbGFicyh4PSdHbG9iYWwgdGltZSAobnMpJywgeT0neSAobW0pJywgc3VidGl0bGU9Ik1lYXN1cmVkIGJ5IEFyYyBoaXRzIGFuZCBSaW5nIFRyYWNraW5nIFBsYW5lcyIpCiMKZ3JpZC5hcnJhbmdlKHAxLCBwMikKYGBgCg==